/**
 * 基于jquery的选项卡插件
 * Author: 陆楚良
 * Version: 1.0.2
 * Date: 2015/03/12
 * QQ: 519998338
 *
 * https://git.oschina.net/luchg/jquery.tab.js.git
 *
 * License: http://www.apache.org/licenses/LICENSE-2.0
 */

// 国际惯例，写在闭包里面，感叹号版闭包，不需要过多解释吧，装逼的写法
!function(){

	// 写在一个函数了里，主要用于判断脚本所在环境后再执行
	function tab($){

		// 此句可防止被重复执行或多次加载同一文件，当然，除非你代码真的很不严谨，不然基本上是不需要这句的
		if(!$.fn.tab){
			$.fn.tab = function(op){

				// 养成使用each的好习惯，这样写出的插件才能在一个拥有多元素的选择器下正常使用
				this.each(function(){

					// 合并默认配置到变量c，extend的作用请参阅jQuery的文档
					var c = $.extend({
							eType:"click",		// 绑定的事件名
							card:"",			// 菜单选项选择器
							panel:"",			// 容器选择器
							curClass:"z-crt",	// 菜单选项高亮样式名
							extend:null			// 扩展专用（下文用到时候再详细介绍）
						}, op),

						// 创建选项卡对象，所有数据都将存于此对象中，为什么这么放？多余？不多余，为扩展使用的，下文扩展时候再讲
						d = {config:c};
					
					// 初始化菜单选项选择器，让它成为jQuery对象
					c.card = $(c.card, this);

					// 初始化容器选择器，让它成为jQuery对象
					c.panel= $(c.panel,this);

					// 初始化当前显示的选项卡索引以及上次显示的选项卡索引（根据高亮样式名读取索引即可）
					d.lastIndex = d.index = c.card.filter("."+c.curClass).index();

					// 显示方法，接收一个索引参数，表示要显示第几个选项卡，索引起始值0
					d.show = function(i){

						// 如果要显示的选项卡不是当前选项卡时候，才给它执行，毕竟嘛，我都已经把你给显示了，再显示你也看不到效果，多余，对吧
						if(i!=d.index){

							// 将当上次选项卡索引存为当前选项卡索引
							d.lastIndex = d.index;

							// 将当前选项卡索引存为即将要显示的选项卡索引
							d.index = i;

							// 提取出上次的菜单选项删除高亮样式，提取出将上次的内容容器隐藏
							c.card.eq(d.lastIndex).removeClass(c.curClass);
							c.panel.eq(d.lastIndex).hide();

							// 提取出即将要显示的菜单选项删除高亮样式，提取出将即将要显示的内容容器隐藏
							c.card.eq(i).addClass(c.curClass);
							c.panel.eq(i).show();
						}
					};
					// 遍历菜单绑定事件，使用遍历方法取出的i值比$(this).index()获取到的更准确
					c.card.each(function(i){
						$(this).on(c.eType, function(){
							// 并执行show方法，传递当前选项菜单的索引
							d.show(i);
						});
					});

					// 扩展！
					// 这里要重点讲一讲了
					// 其实实现是很简单的：如果extend属性是个函数，则执行，利用call方法修改函数中的this，使得函数中的this为d对象
					// 一个简单的选项卡而已，需要什么扩展呢？
					// 需求总是不断地在变，代码的变化永远赶不上产品修改需求的速度，我总不能为了一个新的需求去频繁修改一个插件
					// 你可能会遇见这么一种需求：在我切换显示了某个选项之后，我想用js监听到以用于其它用途。
					// 如:
					//     容器内有大量图片，我想将这些图片懒加载化，但是，网上的懒加载插件它不知道我将该容器切换显示了，因而里面
					//     的图片一直是显示正在加载的圈圈，我不滚动一下页面它就一直这么害羞不出来，怎么办？
					// 因此该方法诞生，之所以我不在show里做扩展，是因为我想做一个实现最简单，功能却更强的扩展
					// 此时，我们只需要这么做：
					// $(xxx).tab({
					//     xxxx,
					//     extend:function(){
					//         var show = this.show;
					//         this.show = function(i){
					//             show(i);
					//             alert("您切换了选项卡："+i);
					//         };
					//     }
					// });
					// 原理很简单，“纂改”，没错，就是纂改d对象中的show方法！不仅可以这样，还可以读取、纂改d对象中的所有数据，当然，
					// 本插件也没强大到可以安全的修改任何数据，“纂改”是很强大，但是使用需谨慎！
					// 其实，上文的那个懒加载问题当然也有其它办法解决，比如我给选项菜单绑定相应的事件就可以解决了。不过，extend的
					// 目的可不是这么简单，extend的目上文也说得差不多了，就是：允许你在安全使用条件下读取或纂改我所曝光的任何数据！
					// 到此，你应该知道我为何将各种方法、数据都存到d对象里了吧，为的就是这个extend
					$.type(c.extend)=="function" && c.extend.call(d);
				});
				
				// 返回this，实际就是返回jQuery选择器对象，使得可以进行连贯操作，如 $(xxx).tab({xxx}).xxx()
				return this;
			};
		}

		// 返回jQuery给RequireJS && SeaJS && GlightJS && NodeJS的一个返回而已，并无实际用意
		return $;
	};

	/**
	 * 原理：通过define判断是否为amd模式，通过exports判断是否为NodeJS模式，最后使用原始模式
	 */
	// RequireJS && SeaJS && GlightJS
	// GlightJS: https://git.oschina.net/luchg/Glight.js.git
	if(typeof define==="function"){
		define(function(){return tab});
	// NodeJS
	}else if(typeof exports!=="undefined"){
		module.exports = tab;
	}else{
		// 原生环境：直接执行函数，从全局变量中取到jQuery
		tab(this.jQuery);
	}
}();